#include "message_bond_impl.h"
#include "../message_kernel_impl.h"
#include <core/sharedata/login_data.h>
#include <core/Utility.h>
#include <qbprotocol/include/SSMsgStruct.h>
#include <qbprotocol/include/RequestNetWrapper.h>
#include <qbnet/source/network_service_impl.h>

#ifndef WIN32
#include <arpa/inet.h>
#else
#pragma comment(lib, "ws2_32.lib")
#endif


namespace qb
{
    CMessageBondImpl::CMessageBondImpl()
        : m_spNetworkService(NULL)
        , m_spMessageKernel(NULL)
        , m_spMsgProcess(nullptr)
	{
	}

    CMessageBondImpl::~CMessageBondImpl()
	{
	}

	STDMETHODIMP_(void) CMessageBondImpl::OnResponse(THIS_ int32_t msgtype, qb::ProcessMessage msp)
	{
        assert(msgtype == E_FID_SERVER_QPID || msgtype == E_FID_SERVER_QPID_JAVA);
        if (msp.getBuff() == nullptr || msp.getLen() <= 0)
            return;

		int iFunid = 0;

		xMsgHeadAck_t xHead;
		memcpy(&xHead, msp.getBuff(), sizeof(xHead));
		xHead.msgtype = ntohl(xHead.msgtype);
		xHead.retcode = ntohs(xHead.retcode);
		xHead.idx = ntohs(xHead.idx);
		xHead.num = ntohs(xHead.num);

		m_Paser.Clean();

        SSAckMsg stAck;
		iFunid = m_Paser.GetMessageType(msp.getBuff() + sizeof(xHead), msp.getLen() - sizeof(xHead), stAck);
        stAck.m_FuncID = iFunid;
        DecodeFunc df = m_msgDecodeFuncs[iFunid];
        if (df)
        {
            m_Paser.SetDecodeFunc(df);
            stAck.m_pRet = m_Paser.DecodeMessage(&stAck);
            if (stAck.m_pRet == nullptr)
                log_warning("Message Decode NULL: %d", iFunid);
        }
        else
        {
            log_warning("Message No Decoder: %d", iFunid);
            //assert(false && "No Decode Func！");
        }

        {
            Locker lock(m_lock);
            auto iters = m_msgProcessors.equal_range(iFunid);
            for (auto iter = iters.first; iter != iters.second; ++iter)
            {
                iter->second->OnResponse(iFunid, stAck);
            }
        }
        if (m_specificMsgProcesser)
            m_specificMsgProcesser->OnResponse(iFunid, stAck);

        //清理数据
        if (df && stAck.m_pRet)
        {
            static ProtoMessage s_dumy_msg;
            void* p = df(stAck.m_FuncID, s_dumy_msg, stAck.m_pRet);
            assert(p == nullptr);
        }
	}

	STDMETHODIMP_(bool) CMessageBondImpl::UnRegisterMsgProcessor(THIS_ int funcId, IQpidMessageProcessor* p)
	{
        if (p == nullptr)
            return false;
        Locker lock(m_lock);
        auto iters = m_msgProcessors.equal_range(funcId);
        for (auto iter = iters.first; iter != iters.second; ++iter)
        {
            if (iter->second == p)
            {
                m_msgProcessors.erase(iter);
                break;
            }
        }

        return true;
	}

	STDMETHODIMP_(bool) CMessageBondImpl::RegisterMsgProcessor(THIS_ int funcId, IQpidMessageProcessor* p)
	{
        if (p == nullptr)
            return false;

		Locker lock(m_lock);
        m_msgProcessors.insert({ funcId, p });
        return true;
	}

	STDMETHODIMP_(bool) CMessageBondImpl::RegisterDecodeFunc(int v, DecodeFunc f)
	{
        if (f == nullptr)
            return false;
        m_msgDecodeFuncs[v] = f;
		return false;
	}


	STDMETHODIMP_(int32_t) CMessageBondImpl::Create(THIS_ INetworkService* ins, IMessageKernel* kernel, IMessageProcess* process)
	{
        m_spNetworkService = ins;
        m_spMessageKernel = kernel;
        m_spMsgProcess = process;
        AttachModules();

        m_networkHeartBeat.Create();
		return 0;
	}

    STDMETHODIMP_(int32_t) CMessageBondImpl::Destory(THIS_)
	{
        m_networkHeartBeat.Destroy();
        DetachModules();
		return 0;
	}

    int32_t CMessageBondImpl::RequestHeartBeat()
    {
        //TODO: 移走到AUTH模块
		xMsgHeadReq_t xhead;
		xhead.msgtype = htonl(E_FID_CS_HEARTBEAT);

		int off = 0;
		char sndBuf[Y_RD_SERVICE_MESSAGE_BLOCK_LEN];
		memset(sndBuf, 0x00, Y_RD_SERVICE_MESSAGE_BLOCK_LEN);
		rdMessage::bPack((char*)&xhead, sizeof(xhead), (char*)nullptr, 0, sndBuf, &off);

		return m_spMessageKernel->Send(qb::loginData::instance().ConnectID(), sndBuf, off);
    }


    STDMETHODIMP_(void) CMessageBondImpl::SetSpecificMsgProcessor(IQpidMessageProcessor* p)
	{
        m_specificMsgProcesser = p;
	}

	void CMessageBondImpl::OnHeartBeat()
	{
		if (eNetStatus_Done != loginData::instance().GetCurrentStatus())
		{
			return;
		}

		RequestHeartBeat();
	}

    void CMessageBondImpl::AttachModules()
    {
        m_networkHeartBeat.RegisterNotify(this);
        if (m_spMsgProcess)
        {
            m_spMsgProcess->RegisterMsgProcessorOnThread(E_FID_SERVER_QPID, this);
            m_spMsgProcess->RegisterMsgProcessorOnThread(E_FID_SERVER_QPID_JAVA, this);
        }
            
    }

    void CMessageBondImpl::DetachModules()
    {
		if (m_spMsgProcess)
		{
            m_spMsgProcess->UnRegisterMsgProcessorOnThread(E_FID_SERVER_QPID, this);
            m_spMsgProcess->UnRegisterMsgProcessorOnThread(E_FID_SERVER_QPID_JAVA, this);
		}

        m_networkHeartBeat.DeRegisterNotify(this);

        m_spNetworkService = NULL;
    }
}
